interface Levels {
	trace: logStyle;
	debug: logStyle;
	info: logStyle;
	warn: logStyle;
	error: logStyle;
	fatal: logStyle;
	off: logStyle;
}

enum LogEnum {
	OFF = 0,
	TRACE = 1,
	DEBUG = 2,
	INFO = 3,
	WARN = 4,
	ERROR = 5,
	FATAL = 6
}
enum LogType {
	OFF = 'off',
	TRACE = 'trace',
	DEBUG = 'debug',
	INFO = 'info',
	WARN = 'warn',
	ERROR = 'error',
	FATAL = 'fatal'
}

interface logStyle {
	levelStyle: string;
	dateStyle: string;
	methodStyle: string;
	lineStyle: string;
	infoStyle: string;
	level: LogEnum;
	name: LogType;
}

class Logger {
	levels: Levels;
	useLevel: number;
	constructor(level: number = 1) {
		this.useLevel = level;
		this.levels = {
			trace: {
				levelStyle: 'background:#77787b; color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #2F4F4F; border-radius: 3px 0 0 3px;',
				infoStyle: 'background:#77787b; color: #fff; border-radius: 3px 0 0 3px;',
				level: LogEnum.TRACE,
				name: LogType.TRACE
			},
			debug: {
				levelStyle: 'background: #3c3645;  color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #fff; border-radius: 3px 0 0 3px;',
				infoStyle: 'background: #3c3645; color: #fff; border-radius: 3px 0 0 3px;',
				level: LogEnum.DEBUG,
				name: LogType.DEBUG
			},
			info: {
				levelStyle: 'background: #005831; color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #fff; border-radius: 3px 0 0 3px;',
				infoStyle: 'background: #005831; color: #fff; border-radius: 3px 0 0 3px;',
				level: LogEnum.INFO,
				name: LogType.INFO
			},
			warn: {
				levelStyle: 'background: #f58220; color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #fff; border-radius: 3px 0 0 3px;',
				infoStyle: 'background: #f58220; color: #fff; border-radius: 3px 0 0 3px;',
				level: LogEnum.WARN,
				name: LogType.WARN
			},
			error: {
				levelStyle: 'background: #d71345; color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #fff; border-radius: 3px 0 0 3px;',
				infoStyle: 'background: #d71345; color: #fff; border-radius: 3px 0 0 3px;',
				level: LogEnum.ERROR,
				name: LogType.ERROR
			},
			fatal: {
				levelStyle: 'background: #a7324a; color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #fff; border-radius: 3px 0 0 3px;',
				infoStyle: ' color: #a7324a; border-radius: 3px 0 0 3px;',
				level: LogEnum.FATAL,
				name: LogType.FATAL
			},
			off: {
				levelStyle: 'background: #005831; color: #fff; border-radius: 3px 0 0 3px;',
				dateStyle: 'background: #1475B2; color: #fff; border-radius: 3px 0 0 3px;',
				methodStyle: 'background: #2F4F4F; color: #fff; border-radius: 3px 0 0 3px;',
				lineStyle: 'color: #fff; border-radius: 3px 0 0 3px;',
				infoStyle: 'background: #005831; color: #fff; border-radius: 3px 0 0 3px;',
				level: LogEnum.OFF,
				name: LogType.OFF
			}
		};
	}

	dateFormat(fmt: string, date: Date) {
		let regs;
		const opt = {
			'y+': date.getFullYear().toString(), // 年
			'M+': (date.getMonth() + 1).toString(), // 月
			'd+': date.getDate().toString(), // 日
			'h+': date.getHours().toString(), // 时
			'm+': date.getMinutes().toString(), // 分
			's+': date.getSeconds().toString(), // 秒
			'S+': (date.getTime() % 1000) + '' // 毫秒
			// 有其他格式化字符需求可以继续添加，必须转化成字符串
		};
		for (let k in opt) {
			regs = new RegExp('(' + k + ')').exec(fmt);
			if (regs) {
				fmt = fmt.replace(regs[1], regs[1].length == 1 ? opt[k as keyof typeof opt] : opt[k as keyof typeof opt].padStart(regs[1].length, '0'));
			}
		}
		return fmt;
	}
	print(level: logStyle, msg: string, ...params: any) {
		if (this.useLevel === 0 || level.level < this.useLevel) {
			return;
		}
		let infoArg = [];
		for (let i = 2; i < arguments.length; i++) {
			infoArg = arguments[i];
		}
		let fullMsg = '';
		fullMsg += '%c';
		fullMsg += this.dateFormat('hh:mm:ss.SSS', new Date());
		fullMsg += '%c';
		fullMsg += '[' + level.name + '] ';
		fullMsg += '%c  --  %c';
		fullMsg += msg;
		console.info(fullMsg, level.dateStyle, level.levelStyle, level.lineStyle, level.infoStyle, ...params);
	}
	trace(msg: string, ...params: any) {
		this.print(this.levels.trace, msg, ...params);
	}
	debug(msg: string, ...params: any) {
		this.print(this.levels.debug, msg, ...params);
	}
	info(msg: string, ...params: any) {
		this.print(this.levels.info, msg, ...params);
	}
	warn(msg: string, ...params: any) {
		this.print(this.levels.warn, msg, ...params);
	}
	error(msg: string, ...params: any) {
		this.print(this.levels.error, msg, ...params);
	}
	fatal(msg: string, ...params: any) {
		this.print(this.levels.fatal, msg, ...params);
	}
	setLevel(level: number) {
		this.useLevel = level;
	}
}

export default Logger;
